#pragma once

#include <iostream>
#include <vector>
#include <pthread.h>
#include "Mutex.hpp"
#include "Sem.hpp"

namespace RingBufferModule
{
    using namespace LockModule;
    using namespace SemModule;
    using std::vector;

    template <typename T>
    class RingBuffer
    {
    private:
        vector<T> _ring; // 环形缓冲区
        int _capacity;   // 容量
        int _p_step;     // 生产者位置
        int _c_step;     // 消费者位置
        Mutex _p_lock;   // 生产者锁
        Mutex _c_lock;   // 消费者锁
        Sem _data_sem;   // 数据信号量
        Sem _space_sem;  // 空间信号量
    public:
        RingBuffer(int capacity)
            : _capacity(capacity), _p_step(0), _c_step(0), _data_sem(0), _space_sem(capacity)
        {
            _ring.resize(_capacity);
        }
        ~RingBuffer() {}
        void Equeue(const T& in)
        {
            //获取信号量
            _space_sem.P();
            //加锁
            _p_lock.Lock();
            //生产
            _ring[_p_step] = in;
            _p_step = (_p_step + 1) % _capacity;
            //解锁
            _p_lock.UnLock();
            //释放信号量
            _data_sem.V();
        }

        void Pop(T *out)
        {
            //获取信号量
            _data_sem.P();
            //加锁
            _c_lock.Lock();
            //消费
            *out = _ring[_c_step];
            _c_step = (_c_step + 1) % _capacity;
            //解锁
            _c_lock.UnLock();
            //释放信号量
            _space_sem.V();
        }
    };
}